package com.bluesky.plum.uimodels.standard;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.bluesky.plum.richdomain.RichDomainField;
import com.bluesky.plum.richdomain.RichDomainFields;
import com.bluesky.plum.richdomain.RichDomainMethod;
import com.bluesky.plum.uimodels.standard.components.Button;
import com.bluesky.plum.uimodels.standard.components.CheckBox;
import com.bluesky.plum.uimodels.standard.components.DateTimePicker;
import com.bluesky.plum.uimodels.standard.components.EventListener;
import com.bluesky.plum.uimodels.standard.components.Label;
import com.bluesky.plum.uimodels.standard.components.ListBox;
import com.bluesky.plum.uimodels.standard.components.ObjectEditor;
import com.bluesky.plum.uimodels.standard.components.SpinBox;
import com.bluesky.plum.uimodels.standard.components.Table;
import com.bluesky.plum.uimodels.standard.components.TextArea;
import com.bluesky.plum.uimodels.standard.components.TextBox;
import com.bluesky.plum.uimodels.standard.components.containers.Panel;
import com.bluesky.plum.uimodels.standard.components.containers.form.Form;
import com.bluesky.plum.uimodels.standard.components.containers.form.FormBuilder;
import com.bluesky.plum.uimodels.standard.components.containers.layout.Grid;
import com.bluesky.plum.uimodels.standard.components.containers.layout.HorizontalBox;
import com.bluesky.plum.uimodels.standard.components.containers.layout.VerticalBox;
import com.bluesky.plum.uimodels.standard.components.containers.window.Dialog;
import com.bluesky.plum.uimodels.standard.components.containers.window.MainWindow;
import com.bluesky.plum.uimodels.standard.components.menu.Menu;
import com.bluesky.plum.uimodels.standard.components.menu.MenuBar;
import com.bluesky.plum.uimodels.standard.components.menu.MenuItem;
import com.bluesky.plum.uimodels.standard.components.objectBrowser.ObjectCollectionEditor;
import com.bluesky.plum.uimodels.standard.components.objectBrowser.ObjectSelector;
import com.bluesky.plum.validate.ParameterValidateFailedException;

public class StandardUIComponentBuilder implements UIComponentBuilder {

	protected Map<StandardUIComponentType, Class> componentTypeMap;

	private long componentSequence;

	public StandardUIComponentBuilder() {

		componentTypeMap = new HashMap<StandardUIComponentType, Class>();

		register();

		componentSequence = 0;
	}

	protected long getNextComponentSequence() {
		long s = componentSequence;
		componentSequence++;
		return s;
	}

	protected void register() {

		// nonfield component
		componentTypeMap.put(StandardUIComponentType.ListBox, ListBox.class);
		componentTypeMap.put(StandardUIComponentType.Table, Table.class);

		// field component
		componentTypeMap.put(StandardUIComponentType.Checkbox, CheckBox.class);
		componentTypeMap.put(StandardUIComponentType.SpinBox, SpinBox.class);
		componentTypeMap.put(StandardUIComponentType.TextBox, TextBox.class);
		componentTypeMap.put(StandardUIComponentType.DateTimePicker,
				DateTimePicker.class);
		componentTypeMap.put(StandardUIComponentType.ObjectBrowser,
				ObjectSelector.class);
		componentTypeMap.put(StandardUIComponentType.ObjectEditor,
				ObjectEditor.class);
		componentTypeMap.put(StandardUIComponentType.ObjectCollectionEditor,
				ObjectCollectionEditor.class);

		componentTypeMap.put(StandardUIComponentType.Label, Label.class);
		componentTypeMap.put(StandardUIComponentType.TextArea, TextArea.class);

		componentTypeMap.put(StandardUIComponentType.Button, Button.class);
		componentTypeMap.put(StandardUIComponentType.Menu, Menu.class);
		componentTypeMap.put(StandardUIComponentType.MenuItem, MenuItem.class);
		componentTypeMap.put(StandardUIComponentType.MenuBar, MenuBar.class);
		componentTypeMap.put(StandardUIComponentType.MainWindow,
				MainWindow.class);
		componentTypeMap.put(StandardUIComponentType.Dialog, Dialog.class);
		componentTypeMap.put(StandardUIComponentType.Panel, Panel.class);
		componentTypeMap.put(StandardUIComponentType.Form, Form.class);

		// layout
		componentTypeMap.put(StandardUIComponentType.HorizontalBox,
				HorizontalBox.class);
		componentTypeMap.put(StandardUIComponentType.VerticalBox,
				VerticalBox.class);
		componentTypeMap.put(StandardUIComponentType.Grid, Grid.class);

	}

	/*
	 * after the component instance is created, we have a chance to do sth.
	 */
	protected void afterCreateInstance(UIComponent uic){
		//such as load ui definition from html/xml
	}
	
	@Override
	public UIComponent createNonFieldComponent(StandardUIComponentType type) {

		try {
			// System.out.println("in createNonFieldComponent(), start "+type.name());

			Class clazz = componentTypeMap.get(type);
			UIComponent uic = (UIComponent) clazz.newInstance();
			uic.setComponentType(type);
			
			//event
			afterCreateInstance(uic);
			
			uic.setId(type.toString() + "_"
					+ String.valueOf(getNextComponentSequence()));
			uic.setUiComponentBuilder(this);
			
			uic.initialize();

			return uic;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}

	}

	public FieldUIComponent createComponent(RichDomainField field) {

		try {
			StandardUIComponentType componentType = field.fieldType
					.getComponentType(field);
			
			if (componentType == null) {
				System.out.println("componentType is null:");
			}
			
			Class clazz = componentTypeMap.get(componentType);
			if (clazz == null) {
				System.out.println("clazz is null:");
			}

			Constructor ctor = clazz.getConstructor(RichDomainField.class);
			FieldUIComponent uic = (FieldUIComponent) ctor.newInstance(field);
			uic.setComponentType(componentType);
			
			//event
			afterCreateInstance(uic);
			
			uic.setId(componentType.toString() + "_"
					+ String.valueOf(getNextComponentSequence()) + "_"
					+ field.name);
			uic.setUiComponentBuilder(this);

			
			uic.initialize();
			
			return uic;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new RuntimeException("createComponnt fail:" + e.getMessage());
		}

	}

	@Override
	public FieldUIComponent[] createComponents(RichDomainField[] fields) {

		FieldUIComponent[] rslt = new FieldUIComponent[fields.length];
		for (int i = 0; i < fields.length; i++) {

			rslt[i] = createComponent(fields[i]);
		}
		return rslt;
	}

	/**
	 * other implementations(like HTML and Swing) should not override this.
	 */
	@Override
	public Form createForm(final RichDomainMethod rdm) {
		final Method m = rdm.method;

		final RichDomainFields rdfs = RichDomainFields.createFromMethod(rdm);

		final FieldUIComponent[] uics = createComponents(rdfs.getFields()
				.getList().toArray(new RichDomainField[] {}));

		final Form form;
		try {
			FormBuilder fb = (FormBuilder) rdm.formBuilder.newInstance();

			form = fb.createForm(this, rdm);
			form.setComponentType(StandardUIComponentType.Form);
			form.setId(StandardUIComponentType.Form.toString() + "_"
					+ String.valueOf(getNextComponentSequence()));
		} catch (Exception e1) {
			e1.printStackTrace();
			throw new RuntimeException(e1);
		}

		// auto create label pair
		form.addFieldComponents(uics);

		form.addButton("Submit", new EventListener() {
			@Override
			public void process() {
				// gather parameters from Form
				Object[] parameterValues = new Object[uics.length];
				for (int i = 0; i < uics.length; i++)
					parameterValues[i] = uics[i].getDomainFieldValue();

				Class<?> returnType = m.getReturnType();

				try {

					Object result = m.invoke(rdm.object, parameterValues);

					RichDomainField returnRdf = rdfs.getReturnField();
					returnRdf.value = result;

					form.getReturnValuePanel().removeAllChildren();
					form.getReturnValuePanel().addChildComponent(
							createComponent(returnRdf));

					// if (returnType.toString().equals("void"))
					// form.setResultMessage("Success");
					// else {
					// form.setResultMessage("Success:" + result);
					// }

				} catch (Exception e) {

					e.printStackTrace();
					
					if(e instanceof ParameterValidateFailedException){
						
						
					}

					TextArea ta = (TextArea) createNonFieldComponent(StandardUIComponentType.TextArea);
					ta.setCaption(e.toString());

					form.getReturnValuePanel().removeAllChildren();
					form.getReturnValuePanel().addChildComponent(ta);

				}

			}
		});

		form.addButton("Cancel", new EventListener() {
			@Override
			public void process() {

			}
		});

		// add result panel

		/**
		 * trigger the event
		 */
		form.onCreate();

		return form;
	}
}
